#include "lcd_driver.h"
#include "uart.h"
#include "time.h"
#include "string.h"
#include "adc.h"
#include "gps.h"
#include "lcd.h"
#include "eeprom.h"
#include <stdio.h>


//unsigned char code test[27] = "$PSRF100,0,9600,8,1,0*0C\r\n\0";
//sbit ERR_LED = P0^6;

void ADC_Init()
{
    AMX0P     = 0x10;
    AMX0N     = 0x11;
    //ADC0CF    = 0xFC;
    ADC0CN    = 0xC0;
	REF0CN    = 0x0E;
}

void UART_Init()
{
    SCON0     = 0x10;
	
}

void SPI_Init()
{
    SPI0CFG   = 0x40;
    SPI0CN    = 0x01;
	SPI0CKR   = 0x05;
}

void Timer_Init()
{
   
    TCON      = 0x40;
    TMOD      = 0x20;
    CKCON     = 0x01;
    TH1       = 0xB0;

	TMR3CN    = 0x05;
	TMR3RLH   = 0xF0;
    TMR3H     = 0xF0;
	
	hours = 0;
	minutes = 0;
	seconds = 0;
}

void Interrupts_Init()
{
    IE        = 0xD0;
    EIE1      = 0x88;
}

// Peripheral specific initialization functions,
// Called from the Init_Device() function
void Port_IO_Init()
{
    // P0.0  -  Skipped,     Push-Pull,  Digital  LCD_RS
    // P0.1  -  Skipped,     Open-Drain, Digital  LCD_RW
    // P0.2  -  Skipped,     Open-Drain, Analog
    // P0.3  -  Skipped,     Open-Drain, Analog
    // P0.4  -  TX0 (UART0), Open-Drain, Digital
    // P0.5  -  RX0 (UART0), Open-Drain, Digital
    // P0.6  -  SCK  (SPI0), Push-Pull,  Digital
    // P0.7  -  Skipped,     Push-Pull,  Digital

    // P1.0  -  Skipped,     Push-Pull,  Digital
    // P1.1  -  Skipped,     Push-Pull,  Digital
    // P1.2  -  Skipped,     Push-Pull,  Digital
    // P1.3  -  Skipped,     Push-Pull,  Digital
    // P1.4  -  MISO (SPI0), Push-Pull,  Digital
    // P1.5  -  MOSI (SPI0), Push-Pull,  Digital
    // P1.6  -  Unassigned,  Push-Pull,  Digital
    // P1.7  -  Unassigned,  Push-Pull,  Digital  LCD_E

	//P0		  = 0x00;
	//P1		  = 0x00;
    P0MDIN    = 0xF3; //1111 0011
    P0MDOUT   = 0xDF; //1101 1111
    P1MDOUT   = 0xFF; //1111 1111
    P2MDOUT   = 0x00; //0000 0000
    P0SKIP    = 0x8F;
    P1SKIP    = 0x0F;
    XBR0      = 0x03;
    XBR1      = 0x40;
	//P0		  = 0xFF;
	//P1		  = 0xFF;
}


void Oscillator_Init()
{
    int xdata i	= 0;
    OSCXCN		= 0x61;
    
	for (i = 0; i < 3000; i++);  // Wait 1ms for initialization
	//#warning not waiting for the XTAL to stabilize
	while ((OSCXCN & 0x80) == 0);
    
	//CLKSEL		= 0x01;
}

// Initialization function for device,
// Call Init_Device() from your main program
void Init_Device(void)
{
	Port_IO_Init();
	Timer_Init();	
	Interrupts_Init();
	Oscillator_Init();
	ADC_Init();

	SPI_Init();
	init_eeprom();
	lcd_initialize();	
	UART_Init();
	have_fix = 0;
	uartBufferIndex = 0;
	//memset(uartBuffer, 0, UART_BUFFER_SIZE);
}

void main(){
	
	int curr_temp = 0;
	float my_odo;
	unsigned char lcd_inited = 0;
	unsigned char spinner[1];
	PCA0MD &= ~0x40; // disable watchdog
	Init_Device();
	my_odo = odometer;
	lcd_clear();
	lcd_write_string_at_pos("ACQUIRING GPS SIGNAL", 1, 0, 20);	 
	while(1){
		//this is roughly what the output looks like
								 //01234567890123456789
		//lcd_write_string_at_pos(" 45.1234, -111.3455 \0", 1, 0, 20);
		//lcd_write_string_at_pos(" 78mph 14,239ft 270\1\0",2, 0, 20);
		//lcd_write_string_at_pos("104\1F 183,123 1999.9",  3, 0, 20);
		//lcd_write_string_at_pos("/GPRMC       00:00:59");
		sleep();
		lcd_write_string_at_pos(get_time_str(), 4, 12, 8);
		//ERR_LED = ~ERR_LED;
		
		switch(sentence_ready){
			//glean lat, lon, speed, heading, time, date
			case GPRMC_READY:
				process_gprmc();		
			break;
			//get altitude
			case GPGGA_READY:
				process_gpgga();
			break;
			case GPS_DUMP:
				dump_gps();
				sentence_ready = 0;
			break;
		}

		//tell the observer that we're looking for a fix if we don't have one
		if(!have_fix){
			lcd_write_string_at_pos("ACQUIRING GPS SIGNAL", 1, 0, 20);		
		}

		//give some feedback as to how the GPS is performing
		if(sentence_ready){
			switch(seconds % 4){
				case 0:
					spinner[0] = '|';
				break;
				case 1:
					spinner[0] = '/';
				break;
				case 2:
					spinner[0] = '-';
				break;
				default:
					spinner[0] = 0;
				break;
			}
			
			lcd_write_string_at_pos(spinner, 4, 0, 1);
			lcd_write_string_at_pos(uartBuffer, 4, 1, 6);
		}

		//I need some filter caps on the control lines for the LCD
		//this is a software workaround to reinitialize after the
		//power source has stabilized
		if(!lcd_inited && seconds == 6){
			lcd_initialize();
			lcd_inited = 1;
		}
		
	
		//update temp
		//EIE1 = 0x88;
		adc_sampled = 0;
		AD0BUSY = 1;
		adc_result = 0;
		while(!adc_sampled);
		//EIE1 = 0x80;
		
		curr_temp = (((adc_result - 253) * 9) / 5) + 32;
		memset(pos_line, 0x20, sizeof pos_line);
		if(curr_temp > -50){
			sprintf(pos_line, "%d\1F", curr_temp);
			lcd_write_string_at_pos(pos_line, 3, 0, 4);
		}
		
		
		if(sentence_ready && gl.header == GPS_LOG_HEADER){
			//save gps data to RAM buffer every 5 seconds
			if(seconds % 5 == 0)
				save_gps_log(0);
			//force a gps flash page write every minute
			if(seconds == 57)
				save_gps_log(1);
		}	

	   	//let the next sentence come through
		sentence_ready = 0;

		//save the odometer to flash every 30 seconds if we've moved at least 0.1 miles
		if(seconds == 30 && odometer - my_odo > 0.1f){
			save_odometer();
			my_odo = odometer;
		}

	
		
	}

}